/*
 * $Id: EditorActions.java,v 1.6 2009/12/08 19:52:50 gaudenz Exp $
 * Copyright (c) 2001-2009, JGraph Ltd
 * 
 * All rights reserved.
 * 
 * See LICENSE file for license details. If you are unable to locate
 * this file please contact info (at) jgraph (dot) com.
 */
package com.magnificent.panda.ui.editor;

import com.magnificent.panda.model.generator.log.AxionAgentLogParser;
import com.silverhaze.commons.ui.dialogs.DialogFactory;
import com.silverhaze.commons.utils.collections.list.MetaList;
import com.silverhaze.commons.utils.other.Pair;
import com.magnificent.graph.analysis.mxDistanceCostFunction;
import com.magnificent.graph.analysis.mxGraphAnalysis;
import com.magnificent.graph.io.mxCodec;
import com.magnificent.graph.model.Cell;
import com.magnificent.graph.model.CellRole;
import com.magnificent.graph.model.mxIGraphModel;
import com.magnificent.graph.util.mxCellRenderer;
import com.magnificent.graph.util.mxConstants;
import com.magnificent.graph.util.mxResources;
import com.magnificent.graph.util.mxUtils;
import com.magnificent.graph.view.mxGraph;
import com.magnificent.panda.model.entity.FlowActor;
import com.magnificent.panda.model.generator.log.TaxiLogParser;
import com.magnificent.panda.ui.GraphComponent;
import com.magnificent.panda.ui.GraphEditor;
import com.magnificent.panda.ui.GraphOutline;
import com.magnificent.panda.ui.handler.mxConnectionHandler;
import com.magnificent.panda.ui.util.mxGraphActions;
import com.magnificent.panda.ui.view.CellEditor;
import org.w3c.dom.Document;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;

/**
 * @author Administrator
 */
public class EditorActions {

    /**
     * @param e
     * @return Returns the graph for the given action event.
     */
    public static final BasicGraphEditor getEditor(ActionEvent e) {
        if (e.getSource() instanceof Component) {
            Component component = (Component) e.getSource();

            while (component != null
                    && !(component instanceof BasicGraphEditor)) {
                component = component.getParent();
            }

            return (BasicGraphEditor) component;
        }

        return null;
    }

    public static class LoadTaxiLogsSeparately extends JMenuItem {
        public LoadTaxiLogsSeparately(String text) {
            super(text);

            addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    DialogFactory.fileChooser(new File("C:\\"), new FileFilter() {
                        @Override
                        public boolean accept(File f) {
                            return f.isDirectory() || f.getName().endsWith(".log");
                        }

                        @Override
                        public String getDescription() {
                            return "*.log - Лог файл Такси";
                        }
                    }, true, getEditor(e), new AbstractAction() {
                        public void actionPerformed(ActionEvent e) {
                            TaxiLogParser logParser = new TaxiLogParser();

                            mxGraph graph = GraphEditor.getGraphEditor().getGraphComponent().getGraph();
                            mxIGraphModel graphModel = graph.getModel();
                            Object parent = graph.getDefaultParent();

                            int row = 0;
                            int count = 0;
                            graphModel.beginUpdate();
                            MetaList<Pair<FlowActor, FlowActor>> actors = logParser.parseSeparately(e.getActionCommand());
                            for (Pair<FlowActor, FlowActor> actor : actors) {
                                FlowActor driver = actor.getSecond();
                                FlowActor dispatcher = actor.getFirst();

                                Cell dispatcherCell = (Cell) graph.insertVertex(parent, null, dispatcher.getName(),
                                        60 + 200 * count, 10 + 200 * row, 45, 60, "shape=actor");
                                Cell driverCell = (Cell) graph.insertVertex(parent, null, driver.getName(),
                                        60 + 200 * count, 100 + 200 * row, 45, 60, "shape=actor");
                                Cell functionCell = (Cell) graph.insertVertex(parent, null, "Корреляционная\nфункция",
                                        180 + 200 * count, 65 + 200 * row, 60, 45, "shape=cloud");

                                driverCell.setRole(CellRole.ACTOR);
                                dispatcherCell.setRole(CellRole.ACTOR);
                                functionCell.setRole(CellRole.CORRELATION_FUNCTION);

                                graph.insertEdge(parent, null, "", driverCell, functionCell);
                                graph.insertEdge(parent, null, "", dispatcherCell, functionCell);

                                driverCell.setFlowActor(driver);
                                dispatcherCell.setFlowActor(dispatcher);

                                driverCell.getFlowActor().setEvents(driver.getEvents());
                                dispatcherCell.getFlowActor().setEvents(dispatcher.getEvents());

                                count++;
                                if (count == 6) {
                                    row++;
                                    count = 0;
                                }
                            }
                            graphModel.endUpdate();

                        }
                    }, null, null);
                }
            });
        }
    }

    public static class LoadAxionLogsSeparately extends JMenuItem {
        public LoadAxionLogsSeparately(String text) {
            super(text);

            addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    DialogFactory.fileChooser(new File("C:\\"), new FileFilter() {
                        @Override
                        public boolean accept(File f) {
                            return f.isDirectory() || f.getName().endsWith(".log");
                        }

                        @Override
                        public String getDescription() {
                            return "*.log - Лог файл МАС Kg.Axion";
                        }
                    }, true, getEditor(e), new AbstractAction() {
                        public void actionPerformed(ActionEvent e) {
                            AxionAgentLogParser logParser = new AxionAgentLogParser();

                            mxGraph graph = GraphEditor.getGraphEditor().getGraphComponent().getGraph();
                            mxIGraphModel graphModel = graph.getModel();
                            Object parent = graph.getDefaultParent();

                            int row = 0;
                            int count = 0;
                            graphModel.beginUpdate();
                            MetaList<Pair<FlowActor, FlowActor>> actors = logParser.parseSeparately(e.getActionCommand());
                            for (Pair<FlowActor, FlowActor> actor : actors) {
                                FlowActor driver = actor.getSecond();
                                FlowActor dispatcher = actor.getFirst();

                                Cell dispatcherCell = (Cell) graph.insertVertex(parent, null, dispatcher.getName(),
                                        60 + 350 * count, 10 + 200 * row, 45, 60, "shape=actor");
                                Cell driverCell = (Cell) graph.insertVertex(parent, null, driver.getName(),
                                        60 + 350 * count, 100 + 200 * row, 45, 60, "shape=actor");
                                Cell functionCell = (Cell) graph.insertVertex(parent, null, "Корреляционная\nфункция",
                                        200 + 350 * count, 65 + 200 * row, 60, 45, "shape=cloud");

                                driverCell.setRole(CellRole.ACTOR);
                                dispatcherCell.setRole(CellRole.ACTOR);
                                functionCell.setRole(CellRole.CORRELATION_FUNCTION);

                                graph.insertEdge(parent, null, "", driverCell, functionCell);
                                graph.insertEdge(parent, null, "", dispatcherCell, functionCell);

                                driverCell.setFlowActor(driver);
                                dispatcherCell.setFlowActor(dispatcher);

                                driverCell.getFlowActor().setEvents(driver.getEvents());
                                dispatcherCell.getFlowActor().setEvents(dispatcher.getEvents());

                                count++;
                                if (count == 6) {
                                    row++;
                                    count = 0;
                                }
                            }

                            graphModel.endUpdate();
                        }
                    }, null, null);
                }
            });
        }
    }


    public static class LoadTaxiLogs extends JMenuItem {
        public LoadTaxiLogs(String text) {
            super(text);

            addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    DialogFactory.fileChooser(new File("C:\\"), new FileFilter() {
                        @Override
                        public boolean accept(File f) {
                            return f.isDirectory() || f.getName().endsWith(".log");
                        }

                        @Override
                        public String getDescription() {
                            return "*.log - Лог файл Такси";
                        }
                    }, true, getEditor(e), new AbstractAction() {
                        public void actionPerformed(ActionEvent e) {
                            TaxiLogParser logParser = new TaxiLogParser();

                            mxGraph graph = GraphEditor.getGraphEditor().getGraphComponent().getGraph();
                            mxIGraphModel graphModel = graph.getModel();
                            Object parent = graph.getDefaultParent();

                            int row = 0;
                            int count = 0;
                            graphModel.beginUpdate();

                            Pair<FlowActor, List<FlowActor>> actorListPair = logParser.parse(e.getActionCommand());

                            FlowActor dispatcher = actorListPair.getFirst();
                            Cell functionCell = (Cell) graph.insertVertex(parent, null, "Корреляционная\nфункция",
                                    1000, 700, 60, 45, "shape=cloud");
                            Cell dispatcherCell = (Cell) graph.insertVertex(parent, null, dispatcher.getName(),
                                    1000, 800, 45, 60, "shape=actor");
                            graph.insertEdge(parent, null, "", dispatcherCell, functionCell);

                            dispatcherCell.setFlowActor(dispatcher);
                            dispatcherCell.getFlowActor().setEvents(dispatcher.getEvents());

                            for (FlowActor driver : actorListPair.getSecond()) {
                                Cell driverCell = (Cell) graph.insertVertex(parent, null, driver.getName(),
                                        60 + 100 * count, 60 + 100 * row + count * 10, 45, 60, "shape=actor");

                                driverCell.setRole(CellRole.ACTOR);
                                dispatcherCell.setRole(CellRole.ACTOR);
                                functionCell.setRole(CellRole.CORRELATION_FUNCTION);

                                graph.insertEdge(parent, null, "", driverCell, functionCell);
                                graph.insertEdge(parent, null, "", dispatcherCell, functionCell);

                                driverCell.setFlowActor(driver);
                                driverCell.getFlowActor().setEvents(driver.getEvents());

                                count++;
                                if (count == 12) {
                                    row++;
                                    count = 0;
                                }
                            }
                            graphModel.endUpdate();

                        }
                    }, null, null);
                }
            });
        }
    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class ToggleRulersItem extends JCheckBoxMenuItem {
        public ToggleRulersItem(final BasicGraphEditor editor, String name) {
            super(name);
            setSelected(editor.getGraphComponent().getColumnHeader() != null);

            addActionListener(new ActionListener() {
                /**
                 *
                 */
                public void actionPerformed(ActionEvent e) {
                    GraphComponent graphComponent = editor
                            .getGraphComponent();

                    if (graphComponent.getColumnHeader() != null) {
                        graphComponent.setColumnHeader(null);
                        graphComponent.setRowHeader(null);
                    } else {
                        graphComponent.setColumnHeaderView(new EditorRuler(
                                graphComponent,
                                EditorRuler.ORIENTATION_HORIZONTAL));
                        graphComponent.setRowHeaderView(new EditorRuler(
                                graphComponent,
                                EditorRuler.ORIENTATION_VERTICAL));
                    }
                }
            });
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class ToggleGridItem extends JCheckBoxMenuItem {
        /**
         *
         */
        public ToggleGridItem(final BasicGraphEditor editor, String name) {
            super(name);
            setSelected(true);

            addActionListener(new ActionListener() {
                /**
                 *
                 */
                public void actionPerformed(ActionEvent e) {
                    GraphComponent graphComponent = editor
                            .getGraphComponent();
                    mxGraph graph = graphComponent.getGraph();
                    boolean enabled = !graph.isGridEnabled();

                    graph.setGridEnabled(enabled);
                    graphComponent.setGridVisible(enabled);
                    graphComponent.repaint();
                    setSelected(enabled);
                }
            });
        }
    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class ToggleOutlineItem extends JCheckBoxMenuItem {
        /**
         *
         */
        public ToggleOutlineItem(final BasicGraphEditor editor, String name) {
            super(name);
            setSelected(true);

            addActionListener(new ActionListener() {
                /**
                 *
                 */
                public void actionPerformed(ActionEvent e) {
                    final GraphOutline outline = editor.getGraphOutline();
                    outline.setVisible(!outline.isVisible());
                    outline.revalidate();

                    SwingUtilities.invokeLater(new Runnable() {
                        /*
                               * (non-Javadoc)
                               * @see java.lang.Runnable#run()
                               */
                        public void run() {
                            if (outline.getParent() instanceof JSplitPane) {
                                if (outline.isVisible()) {
                                    ((JSplitPane) outline.getParent())
                                            .setDividerLocation(editor
                                                    .getHeight() - 300);
                                    ((JSplitPane) outline.getParent())
                                            .setDividerSize(6);
                                } else {
                                    ((JSplitPane) outline.getParent())
                                            .setDividerSize(0);
                                }
                            }
                        }
                    });
                }
            });
        }
    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class ExitAction extends AbstractAction {

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            BasicGraphEditor editor = getEditor(e);

            if (editor != null) {
                editor.exit();
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class StylesheetAction extends AbstractAction {

        /**
         *
         */
        protected String stylesheet;

        /**
         *
         */
        public StylesheetAction(String stylesheet) {
            this.stylesheet = stylesheet;
        }

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                mxGraph graph = graphComponent.getGraph();
                mxCodec codec = new mxCodec();
                Document doc = mxUtils.loadDocument(EditorActions.class
                        .getResource(stylesheet).toString());

                if (doc != null) {
                    codec.decode(doc.getDocumentElement(), graph
                            .getStylesheet());
                    graph.refresh();
                }
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class ZoomPolicyAction extends AbstractAction {
        /**
         *
         */
        protected int zoomPolicy;

        /**
         *
         */
        public ZoomPolicyAction(int zoomPolicy) {
            this.zoomPolicy = zoomPolicy;
        }

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                graphComponent.setPageVisible(true);
                graphComponent.setZoomPolicy(zoomPolicy);
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class GridStyleAction extends AbstractAction {
        /**
         *
         */
        protected int style;

        /**
         *
         */
        public GridStyleAction(int style) {
            this.style = style;
        }

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                graphComponent.setGridStyle(style);
                graphComponent.repaint();
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class GridColorAction extends AbstractAction {

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                Color newColor = JColorChooser.showDialog(graphComponent,
                        mxResources.get("gridColor"), graphComponent
                                .getGridColor());

                if (newColor != null) {
                    graphComponent.setGridColor(newColor);
                    graphComponent.repaint();
                }
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class ScaleAction extends AbstractAction {

        /**
         *
         */
        protected double scale;

        /**
         *
         */
        public ScaleAction(double scale) {
            this.scale = scale;
        }

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                double scale = this.scale;

                if (scale == 0) {
                    String value = (String) JOptionPane.showInputDialog(
                            graphComponent, "Значение",
                            "Масштаб" + " (%)",
                            JOptionPane.PLAIN_MESSAGE, null, null, "");

                    if (value != null) {
                        scale = Double.parseDouble(value.replace("%", "")) / 100;
                    }
                }

                if (scale > 0) {
                    graphComponent.zoomTo(scale, graphComponent.isCenterZoom());
                }
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class PageSetupAction extends AbstractAction {

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                PrinterJob pj = PrinterJob.getPrinterJob();
                PageFormat format = pj.pageDialog(graphComponent
                        .getPageFormat());

                if (format != null) {
                    graphComponent.setPageFormat(format);
                    graphComponent.zoomAndCenter();
                }
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class PrintAction extends AbstractAction {

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                PrinterJob pj = PrinterJob.getPrinterJob();

                if (pj.printDialog()) {
                    PageFormat pf = graphComponent.getPageFormat();
                    Paper paper = new Paper();
                    double margin = 36;
                    paper.setImageableArea(margin, margin, paper.getWidth()
                            - margin * 2, paper.getHeight() - margin * 2);
                    pf.setPaper(paper);
                    pj.setPrintable(graphComponent, pf);

                    try {
                        pj.print();
                    }
                    catch (PrinterException e2) {
                        System.out.println(e2);
                    }
                }
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class SaveAction extends AbstractAction {

        protected boolean showDialog;
        protected String lastDir = null;

        public SaveAction(boolean showDialog) {
            this.showDialog = showDialog;
        }

        public void actionPerformed(ActionEvent e) {
            BasicGraphEditor editor = getEditor(e);

            if (editor != null) {
                GraphComponent graphComponent = editor.getGraphComponent();
                mxGraph graph = graphComponent.getGraph();
                FileFilter selectedFilter = null;
                FileFilter vmlFileFilter = new DefaultFileFilter(".html",
                        "VML " + mxResources.get("file") + " (.html)");
                String filename = null;

                if (showDialog || editor.getCurrentFile() == null) {
                    String wd;

                    if (lastDir != null) {
                        wd = lastDir;
                    } else if (editor.getCurrentFile() != null) {
                        wd = editor.getCurrentFile().getParent();
                    } else {
                        wd = System.getProperty("user.dir");
                    }

                    JFileChooser fc = new JFileChooser(wd);

                    // Adds the default file format
                    FileFilter defaultFilter = new DefaultFileFilter(".pmf",
                            "Panda Modeling File " + mxResources.get("file")
                                    + " (.pmf)");
                    fc.addChoosableFileFilter(defaultFilter);

                    // Adds special vector graphics formats and HTML
                    fc.addChoosableFileFilter(new DefaultFileFilter(".svg",
                            "SVG " + mxResources.get("file") + " (.svg)"));
                    fc.addChoosableFileFilter(vmlFileFilter);
                    fc.addChoosableFileFilter(new DefaultFileFilter(".html",
                            "HTML " + mxResources.get("file") + " (.html)"));

                    // Adds a filter for each supported image format
                    Object[] imageFormats = ImageIO.getReaderFormatNames();

                    // Finds all distinct extensions
                    HashSet<String> formats = new HashSet<String>();

                    for (int i = 0; i < imageFormats.length; i++) {
                        String ext = imageFormats[i].toString().toLowerCase();
                        formats.add(ext);
                    }

                    imageFormats = formats.toArray();

                    for (int i = 0; i < imageFormats.length; i++) {
                        String ext = imageFormats[i].toString();
                        fc.addChoosableFileFilter(new DefaultFileFilter("."
                                + ext, ext.toUpperCase() + " "
                                + mxResources.get("file") + " (." + ext + ")"));
                    }

                    // Adds filter that accepts all supported image formats
                    fc
                            .addChoosableFileFilter(new DefaultFileFilter.ImageFileFilter(
                                    mxResources.get("allImages")));
                    fc.setFileFilter(defaultFilter);
                    int rc = fc.showDialog(null, mxResources.get("save"));

                    if (rc != JFileChooser.APPROVE_OPTION) {
                        return;
                    } else {
                        lastDir = fc.getSelectedFile().getParent();
                    }

                    filename = fc.getSelectedFile().getAbsolutePath();
                    selectedFilter = fc.getFileFilter();

                    if (selectedFilter instanceof DefaultFileFilter) {
                        String ext = ((DefaultFileFilter) selectedFilter)
                                .getExtension();

                        if (!filename.toLowerCase().endsWith(ext)) {
                            filename += ext;
                        }
                    }

                    if (new File(filename).exists()
                            && JOptionPane.showConfirmDialog(graphComponent,
                            "Файл с таким именем уже существует. Перезаписать?") != JOptionPane.YES_OPTION) {
                        return;
                    }
                } else {
                    filename = editor.getCurrentFile().getAbsolutePath();
                }

                try {
                    String ext = filename
                            .substring(filename.lastIndexOf('.') + 1);

                    if (ext.equalsIgnoreCase("svg")) {
                        mxUtils.writeFile(mxUtils.getXml(mxCellRenderer
                                .createSvgDocument(graph, null, 1, null, null)
                                .getDocumentElement()), filename);
                    } else if (selectedFilter == vmlFileFilter) {
                        mxUtils.writeFile(mxUtils.getXml(mxCellRenderer
                                .createVmlDocument(graph, null, 1, null, null)
                                .getDocumentElement()), filename);
                    } else if (ext.equalsIgnoreCase("html")) {
                        mxUtils.writeFile(mxUtils.getXml(mxCellRenderer
                                .createHtmlDocument(graph, null, 1, null, null)
                                .getDocumentElement()), filename);
                    } else if (ext.equalsIgnoreCase("pmf")
                            || ext.equalsIgnoreCase("xml")) {
                        mxCodec codec = new mxCodec();
                        String xml = mxUtils.getXml(codec.encode(graph
                                .getModel()));

                        mxUtils.writeFile(xml, filename);

                        editor.setModified(false);
                        editor.setCurrentFile(new File(filename));
                    } else {
                        Color bg = null;

                        if ((!ext.equalsIgnoreCase("gif") && !ext
                                .equalsIgnoreCase("png"))
                                || JOptionPane.showConfirmDialog(
                                graphComponent, mxResources
                                        .get("transparentBackground")) != JOptionPane.YES_OPTION) {
                            bg = graphComponent.getBackground();
                        }

                        BufferedImage image = mxCellRenderer
                                .createBufferedImage(graph, null, 1, bg,
                                        graphComponent.isAntiAlias(), null,
                                        graphComponent.getCanvas());

                        if (image != null) {
                            ImageIO.write(image, ext, new File(filename));
                        } else {
                            JOptionPane.showMessageDialog(graphComponent,
                                    mxResources.get("noImageData"));
                        }
                    }
                }
                catch (Throwable ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(graphComponent,
                            ex.toString(),
                            mxResources.get("error"),
                            JOptionPane.ERROR_MESSAGE);
                }
            }
        }
    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class SelectShortestPathAction extends AbstractAction {

        /**
         *
         */
        protected boolean directed;

        /**
         *
         */
        public SelectShortestPathAction(boolean directed) {
            this.directed = directed;
        }

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                mxGraph graph = graphComponent.getGraph();
                mxIGraphModel model = graph.getModel();

                Object source = null;
                Object target = null;

                Object[] cells = graph.getSelectionCells();

                for (int i = 0; i < cells.length; i++) {
                    if (model.isVertex(cells[i])) {
                        if (source == null) {
                            source = cells[i];
                        } else if (target == null) {
                            target = cells[i];
                        }
                    }

                    if (source != null && target != null) {
                        break;
                    }
                }

                if (source != null && target != null) {
                    int steps = graph.getChildEdges(graph.getDefaultParent()).length;
                    Object[] path = mxGraphAnalysis.getInstance()
                            .getShortestPath(graph, source, target,
                                    new mxDistanceCostFunction(), steps,
                                    directed);
                    graph.setSelectionCells(path);
                } else {
                    JOptionPane.showMessageDialog(graphComponent, mxResources
                            .get("noSourceAndTargetSelected"));
                }
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class SelectSpanningTreeAction extends AbstractAction {

        /**
         *
         */
        protected boolean directed;

        /**
         *
         */
        public SelectSpanningTreeAction(boolean directed) {
            this.directed = directed;
        }

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                mxGraph graph = graphComponent.getGraph();
                mxIGraphModel model = graph.getModel();

                Object parent = graph.getDefaultParent();
                Object[] cells = graph.getSelectionCells();

                for (int i = 0; i < cells.length; i++) {
                    if (model.getChildCount(cells[i]) > 0) {
                        parent = cells[i];
                        break;
                    }
                }

                Object[] v = graph.getChildVertices(parent);
                Object[] mst = mxGraphAnalysis.getInstance()
                        .getMinimumSpanningTree(graph, v,
                                new mxDistanceCostFunction(), directed);
                graph.setSelectionCells(mst);
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class ToggleDirtyAction extends AbstractAction {

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                graphComponent.showDirtyRectangle = !graphComponent.showDirtyRectangle;
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class ToggleImagePreviewAction extends AbstractAction {

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                graphComponent.getGraphHandler().setImagePreview(
                        !graphComponent.getGraphHandler().isImagePreview());
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class ToggleConnectModeAction extends AbstractAction {

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                mxConnectionHandler handler = graphComponent
                        .getConnectionHandler();
                handler.setHandleEnabled(!handler.isHandleEnabled());
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class ToggleCreateTargetItem extends JCheckBoxMenuItem {
        /**
         *
         */
        public ToggleCreateTargetItem(final BasicGraphEditor editor, String name) {
            super(name);
            setSelected(true);

            addActionListener(new ActionListener() {
                /**
                 *
                 */
                public void actionPerformed(ActionEvent e) {
                    GraphComponent graphComponent = editor
                            .getGraphComponent();

                    if (graphComponent != null) {
                        mxConnectionHandler handler = graphComponent
                                .getConnectionHandler();
                        handler.setCreateTarget(!handler.isCreateTarget());
                        setSelected(handler.isCreateTarget());
                    }
                }
            });
        }
    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class PromptPropertyAction extends AbstractAction {
        /**
         *
         */
        protected Object target;

        /**
         *
         */
        protected String fieldname, message;

        /**
         *
         */
        public PromptPropertyAction(Object target, String message) {
            this(target, message, message);
        }

        /**
         *
         */
        public PromptPropertyAction(Object target, String message,
                                    String fieldname) {
            this.target = target;
            this.message = message;
            this.fieldname = fieldname;
        }

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof Component) {
                try {
                    Method getter = target.getClass().getMethod(
                            "get" + fieldname);
                    Object current = getter.invoke(target);

                    // TODO: Support other atomic types
                    if (current instanceof Integer) {
                        Method setter = target.getClass().getMethod(
                                "set" + fieldname, new Class[]{int.class});

                        String value = (String) JOptionPane.showInputDialog(
                                (Component) e.getSource(), "Value", message,
                                JOptionPane.PLAIN_MESSAGE, null, null, current);

                        if (value != null) {
                            setter.invoke(target, Integer.parseInt(value));
                        }
                    }
                }
                catch (Exception ex) {
                    ex.printStackTrace();
                }
            }

            // Repaints the graph component
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                graphComponent.repaint();
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class TogglePropertyItem extends JCheckBoxMenuItem {

        /**
         *
         */
        public TogglePropertyItem(Object target, String name, String fieldname) {
            this(target, name, fieldname, false);
        }

        /**
         *
         */
        public TogglePropertyItem(Object target, String name, String fieldname,
                                  boolean refresh) {
            this(target, name, fieldname, refresh, null);
        }

        /**
         *
         */
        public TogglePropertyItem(final Object target, String name,
                                  final String fieldname, final boolean refresh,
                                  ActionListener listener) {
            super(name);

            // Since action listeners are processed last to first we add the given
            // listener here which means it will be processed after the one below
            if (listener != null) {
                addActionListener(listener);
            }

            addActionListener(new ActionListener() {
                /**
                 *
                 */
                public void actionPerformed(ActionEvent e) {
                    execute(target, fieldname, refresh);
                }
            });

            PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {

                /*
                     * (non-Javadoc)
                     * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
                     */

                public void propertyChange(PropertyChangeEvent evt) {
                    if (evt.getPropertyName().equalsIgnoreCase(fieldname)) {
                        update(target, fieldname);
                    }
                }

            };

            if (target instanceof GraphComponent) {
                ((GraphComponent) target)
                        .addPropertyChangeListener(propertyChangeListener);
            } else if (target instanceof mxGraph) {
                ((mxGraph) target)
                        .addPropertyChangeListener(propertyChangeListener);
            }

            update(target, fieldname);
        }

        /**
         *
         */
        public void update(Object target, String fieldname) {
            try {
                Method getter = target.getClass().getMethod("is" + fieldname);
                Object current = getter.invoke(target);

                if (current instanceof Boolean) {
                    setSelected(((Boolean) current).booleanValue());
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         *
         */
        public void execute(Object target, String fieldname, boolean refresh) {
            try {
                Method getter = target.getClass().getMethod("is" + fieldname);
                Method setter = target.getClass().getMethod("set" + fieldname,
                        new Class[]{boolean.class});

                Object current = getter.invoke(target);

                if (current instanceof Boolean) {
                    boolean value = !((Boolean) current).booleanValue();
                    setter.invoke(target, value);
                    setSelected(value);
                }

                if (refresh) {
                    mxGraph graph = null;

                    if (target instanceof mxGraph) {
                        graph = (mxGraph) target;
                    } else if (target instanceof GraphComponent) {
                        graph = ((GraphComponent) target).getGraph();
                    }

                    graph.refresh();
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class HistoryAction extends AbstractAction {

        /**
         *
         */
        protected boolean undo;

        /**
         *
         */
        public HistoryAction(boolean undo) {
            this.undo = undo;
        }

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            BasicGraphEditor editor = getEditor(e);

            if (editor != null) {
                if (undo) {
                    editor.getUndoManager().undo();
                } else {
                    editor.getUndoManager().redo();
                }
            }
        }
    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class FontStyleAction extends AbstractAction {
        /**
         *
         */
        protected boolean bold;

        /**
         *
         */
        public FontStyleAction(boolean bold) {
            this.bold = bold;
        }

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                Component editorComponent = null;

                if (graphComponent.getCellEditor() instanceof CellEditor) {
                    editorComponent = ((CellEditor) graphComponent
                            .getCellEditor()).getEditor();
                }

                if (editorComponent instanceof JEditorPane) {
                    JEditorPane editorPane = (JEditorPane) editorComponent;
                    int start = editorPane.getSelectionStart();
                    int ende = editorPane.getSelectionEnd();
                    String text = editorPane.getSelectedText();

                    if (text == null) {
                        text = "";
                    }

                    try {
                        HTMLEditorKit editorKit = new HTMLEditorKit();
                        HTMLDocument document = (HTMLDocument) editorPane
                                .getDocument();
                        document.remove(start, (ende - start));
                        editorKit.insertHTML(document, start, ((bold) ? "<b>"
                                : "<i>")
                                + text + ((bold) ? "</b>" : "</i>"), 0, 0,
                                (bold) ? HTML.Tag.B : HTML.Tag.I);
                    }
                    catch (Exception ex) {
                        ex.printStackTrace();
                    }

                    editorPane.requestFocus();
                    editorPane.select(start, ende);
                } else {
                    mxIGraphModel model = graphComponent.getGraph().getModel();
                    model.beginUpdate();
                    try {
                        graphComponent.stopEditing(false);
                        graphComponent.getGraph().toggleCellStyleFlags(
                                mxConstants.STYLE_FONTSTYLE,
                                (bold) ? mxConstants.FONT_BOLD
                                        : mxConstants.FONT_ITALIC);
                    }
                    finally {
                        model.endUpdate();
                    }
                }
            }
        }
    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class WarningAction extends AbstractAction {

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                Object[] cells = graphComponent.getGraph().getSelectionCells();

                if (cells != null && cells.length > 0) {
                    String warning = JOptionPane.showInputDialog(mxResources
                            .get("enterWarningMessage"));

                    for (int i = 0; i < cells.length; i++) {
                        graphComponent.setCellWarning(cells[i], warning);
                    }
                } else {
                    JOptionPane.showMessageDialog(graphComponent, mxResources
                            .get("noCellSelected"));
                }
            }
        }
    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class NewAction extends AbstractAction {

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            BasicGraphEditor editor = getEditor(e);

            if (editor != null) {
                if (!editor.isModified()
                        || JOptionPane.showConfirmDialog(editor, "Текущая модель не сохранена. Продолжить создание новой?") == JOptionPane.YES_OPTION) {
                    mxGraph graph = editor.getGraphComponent().getGraph();
                    // Check modified flag and display save dialog
                    Cell root = new Cell();
                    root.insert(new Cell());
                    graph.getModel().setRoot(root);

                    editor.setModified(false);
                    editor.setCurrentFile(null);
                }
            }
        }
    }

    /**
     *
     */
    @SuppressWarnings("serial")
    public static class OpenAction extends AbstractAction {
        /**
         *
         */
        protected String lastDir;

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            BasicGraphEditor editor = getEditor(e);

            if (editor != null) {
                if (!editor.isModified()
                        || JOptionPane.showConfirmDialog(editor, "Текущая модель не сохранена. Продолжить открытие?") == JOptionPane.YES_OPTION) {
                    mxGraph graph = mxGraphActions.getGraph(e);

                    if (graph != null) {
                        String wd = (lastDir != null) ? lastDir : System
                                .getProperty("user.dir");

                        JFileChooser fc = new JFileChooser(wd);

                        // Adds file filter for supported file format
                        FileFilter defaultFilter = new DefaultFileFilter(
                                ".pmf", "Panda Modeling File"
                                        + mxResources.get("file") + " (.pmf)");
                        fc.addChoosableFileFilter(defaultFilter);

                        int rc = fc.showDialog(null, mxResources
                                .get("openFile"));

                        if (rc == JFileChooser.APPROVE_OPTION) {
                            lastDir = fc.getSelectedFile().getParent();

                            try {
                                Document document = mxUtils.parse(mxUtils
                                        .readFile(fc.getSelectedFile()
                                        .getAbsolutePath()));

                                mxCodec codec = new mxCodec(document);
                                codec.decode(document.getDocumentElement(),
                                        graph.getModel());

                                editor.setModified(false);
                                editor.setCurrentFile(fc.getSelectedFile());
                            }
                            catch (IOException e1) {
                                e1.printStackTrace();
                            }

                        }
                    }
                }
            }
        }
    }

    @SuppressWarnings("serial")
    public static class ToggleAction extends AbstractAction {
        protected String key;
        protected boolean defaultValue;

        public ToggleAction(String key) {
            this(key, false);
        }

        public ToggleAction(String key, boolean defaultValue) {
            this.key = key;
            this.defaultValue = defaultValue;
        }

        public void actionPerformed(ActionEvent e) {
            mxGraph graph = mxGraphActions.getGraph(e);

            if (graph != null) {
                graph.toggleCellStyles(key, defaultValue);
            }
        }
    }

    @SuppressWarnings("serial")
    public static class SetLabelPositionAction extends AbstractAction {
        protected String labelPosition, alignment;

        public SetLabelPositionAction(String labelPosition, String alignment) {
            this.labelPosition = labelPosition;
            this.alignment = alignment;
        }

        public void actionPerformed(ActionEvent e) {
            mxGraph graph = mxGraphActions.getGraph(e);

            if (graph != null && !graph.isSelectionEmpty()) {
                graph.getModel().beginUpdate();
                try {
                    // Checks the orientation of the alignment to use the correct constants
                    if (labelPosition.equals(mxConstants.ALIGN_LEFT)
                            || labelPosition.equals(mxConstants.ALIGN_CENTER)
                            || labelPosition.equals(mxConstants.ALIGN_RIGHT)) {
                        graph.setCellStyles(mxConstants.STYLE_LABEL_POSITION,
                                labelPosition);
                        graph.setCellStyles(mxConstants.STYLE_ALIGN, alignment);
                    } else {
                        graph.setCellStyles(
                                mxConstants.STYLE_VERTICAL_LABEL_POSITION,
                                labelPosition);
                        graph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN,
                                alignment);
                    }
                }
                finally {
                    graph.getModel().endUpdate();
                }
            }
        }
    }

    @SuppressWarnings("serial")
    public static class SetStyleAction extends AbstractAction {

        protected String value;

        public SetStyleAction(String value) {
            this.value = value;
        }

        public void actionPerformed(ActionEvent e) {
            mxGraph graph = mxGraphActions.getGraph(e);

            if (graph != null && !graph.isSelectionEmpty()) {
                graph.setCellStyle(value);
            }
        }
    }

    @SuppressWarnings("serial")
    public static class KeyValueAction extends AbstractAction {
        protected String key, value;

        public KeyValueAction(String key) {
            this(key, null);
        }

        public KeyValueAction(String key, String value) {
            this.key = key;
            this.value = value;
        }

        public void actionPerformed(ActionEvent e) {
            mxGraph graph = mxGraphActions.getGraph(e);

            if (graph != null && !graph.isSelectionEmpty()) {
                graph.setCellStyles(key, value);
            }
        }
    }

    @SuppressWarnings("serial")
    public static class PromptValueAction extends AbstractAction {
        protected String key, message;

        public PromptValueAction(String key, String message) {
            this.key = key;
            this.message = message;
        }

        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof Component) {
                mxGraph graph = mxGraphActions.getGraph(e);

                if (graph != null && !graph.isSelectionEmpty()) {
                    String value = (String) JOptionPane.showInputDialog(
                            (Component) e.getSource(),
                            mxResources.get("value"), message,
                            JOptionPane.PLAIN_MESSAGE, null, null, "");

                    if (value != null) {
                        if (value.equals(mxConstants.NONE)) {
                            value = null;
                        }

                        graph.setCellStyles(key, value);
                    }
                }
            }
        }
    }

    @SuppressWarnings("serial")
    public static class AlignCellsAction extends AbstractAction {

        protected String align;

        public AlignCellsAction(String align) {
            this.align = align;
        }

        public void actionPerformed(ActionEvent e) {
            mxGraph graph = mxGraphActions.getGraph(e);

            if (graph != null && !graph.isSelectionEmpty()) {
                graph.alignCells(align);
            }
        }
    }

    @SuppressWarnings("serial")
    public static class AutosizeAction extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            mxGraph graph = mxGraphActions.getGraph(e);

            if (graph != null && !graph.isSelectionEmpty()) {
                graph.updateCellSize(graph.getSelectionCell());
            }
        }
    }

    @SuppressWarnings("serial")
    public static class ColorAction extends AbstractAction {
        protected String name, key;

        public ColorAction(String name, String key) {
            this.name = name;
            this.key = key;
        }

        /**
         *
         */
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                mxGraph graph = graphComponent.getGraph();

                if (!graph.isSelectionEmpty()) {
                    Color newColor = JColorChooser.showDialog(graphComponent,
                            name, null);

                    if (newColor != null) {
                        graph.setCellStyles(key, mxUtils.hexString(newColor));
                    }
                }
            }
        }
    }


    @SuppressWarnings("serial")
    public static class BackgroundImageAction extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                String value = (String) JOptionPane.showInputDialog(
                        graphComponent, mxResources.get("backgroundImage"),
                        "URL", JOptionPane.PLAIN_MESSAGE, null, null,
                        "http://www.callatecs.com/images/background2.JPG");

                if (value != null) {
                    if (value.length() == 0) {
                        graphComponent.setBackgroundImage(null);
                    } else {
                        graphComponent.setBackgroundImage(new ImageIcon(mxUtils
                                .loadImage(value)));
                    }

                    // Forces a repaint of the outline
                    graphComponent.getGraph().repaint();
                }
            }
        }
    }

    @SuppressWarnings("serial")
    public static class BackgroundAction extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                Color newColor = JColorChooser.showDialog(graphComponent,
                        mxResources.get("background"), null);

                if (newColor != null) {
                    graphComponent.getViewport().setOpaque(false);
                    graphComponent.setBackground(newColor);
                }

                // Forces a repaint of the outline
                graphComponent.getGraph().repaint();
            }
        }
    }

    @SuppressWarnings("serial")
    public static class PageBackgroundAction extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                Color newColor = JColorChooser.showDialog(graphComponent,
                        mxResources.get("pageBackground"), null);

                if (newColor != null) {
                    graphComponent.setPageBackgroundColor(newColor);
                }

                // Forces a repaint of the component
                graphComponent.repaint();
            }
        }
    }

    @SuppressWarnings("serial")
    public static class StyleAction extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() instanceof GraphComponent) {
                GraphComponent graphComponent = (GraphComponent) e
                        .getSource();
                mxGraph graph = graphComponent.getGraph();
                String initial = graph.getModel().getStyle(
                        graph.getSelectionCell());
                String value = (String) JOptionPane.showInputDialog(
                        graphComponent, mxResources.get("style"), mxResources
                                .get("style"), JOptionPane.PLAIN_MESSAGE, null,
                        null, initial);

                if (value != null) {
                    graph.setCellStyle(value);
                }
            }
        }
    }
}

  /* converted to utf8 */